﻿namespace FlyVR.Aria2
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Text;

    public sealed class Aria2cRuntime
    {
        #region 私有变量

        private static int aria2cPort = 6800;
        private static string aria2cHost = "localhost";
        private static string downLoadDirectory;
        private static Process aria2cProcess;

        #endregion

        #region 属性

        /// <summary>
        /// Aria2c IP地址
        /// </summary>
        public static string Aria2cHost
        {
            get { return aria2cHost; }
            set
            {
                aria2cHost = value;
                SetAria2cHost(Aria2cHost, Aria2cPort);
            }
        }

        /// <summary>
        /// Aria2c端口
        /// </summary>
        public static int Aria2cPort
        {
            get { return aria2cPort; }
            set
            {
                aria2cPort = value;
                SetAria2cHost(Aria2cHost, aria2cPort);
            }
        }

        /// <summary>
        /// 是否正在运行
        /// </summary>
        public static bool IsLoaded
        {
            get
            {
                Aria2cWarpper.GetVersion();
                return true;
            }
        }


        /// <summary>
        /// 全局下载目录
        /// </summary>
        public static string DownLoadDirectory
        {
            get
            {
                try
                {
                    downLoadDirectory = Aria2cWarpper.DownLoadDirectory;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }

                return downLoadDirectory;
            }
            set
            {
                downLoadDirectory = value;
                try
                {
                    Aria2cWarpper.DownLoadDirectory = downLoadDirectory;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }

        #endregion

        #region 公共方法

        private static Aria2cSettings _Aria2cSettings;

        public static Aria2cSettings Settings
        {
            get { return _Aria2cSettings ?? new Aria2cSettings(); }
            set
            {
                _Aria2cSettings = value;
                SetAria2cHost(value.Aria2Host, value.Aria2Port);
            }
        }

        /// <summary>
        /// 启动服务进程
        /// </summary>
        /// <returns></returns>
       ///public static void Start(Aria2cSettings settings)
       ///{
       ///    Settings = settings;
       ///    Start();
       ///}

        /// <summary>
        /// 启动服务进程
        /// </summary>
        /// <returns></returns>
        public static void Start(Action<string> errorOutputCallback)
        {
            if ( /*!IsLoaded && 外界已经做了检查所以不再检测一遍提升启动速度。*/!File.Exists(Settings.Aria2Path))
                throw new FileNotFoundException(Settings.Aria2Path);

            StartProcess(errorOutputCallback,Settings.Aria2Path, Settings.Aria2Args);
        }

        /// <summary>
        /// 关闭服务进程
        /// </summary>
        public static void ShutDown()
        {
            if (aria2cProcess == null)
                return;
            if (!aria2cProcess.HasExited)
            {
                aria2cProcess.Kill();
                aria2cProcess.Dispose();
            }

            aria2cProcess = null;
        }

        #endregion

        #region 实现

        /// <summary>
        /// 设置host地址
        /// </summary>
        /// <param name="host"></param>
        /// <param name="port"></param>
        private static void SetAria2cHost(string host, int port)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("http://");
            builder.Append(host);
            builder.Append(":");
            builder.Append(port);
            builder.Append("/rpc");

            Aria2cWarpper.Aria2cHost = builder.ToString();
        }


        private static void StartProcess(Action<string> errorOutputCallback,string path, string args = "")
        {
            try
            {
                var aria2Dir = Aria2cTools.GetDirectoryName(path);
                var aria2cName = Aria2cTools.GetFileNameWithoutExtension(path);
                var config = aria2cName + ".conf";
                
                //防止用户误删这个空文件,导致启动失败.
                var session = aria2cName + ".session";
                if(!File.Exists(session))
                    File.WriteAllText(session, "");

                if (string.IsNullOrWhiteSpace(args))
                {
                    if (File.Exists(Path.Combine(aria2Dir, config)))
                    {
                        args = " --conf-path=" + config;
                    }
                    else
                    {
                        args = " --enable-rpc --rpc-listen-all=true --rpc-allow-origin-all --rpc-listen-port=6800 -c -D";
                    }
                }

                errorOutputCallback?.Invoke("path="+path);
                errorOutputCallback?.Invoke("args="+args);
                errorOutputCallback?.Invoke("dir="+aria2Dir);
                
                aria2cProcess = new Process();
                aria2cProcess.StartInfo.FileName = path;
                aria2cProcess.StartInfo.Arguments = args;
                aria2cProcess.StartInfo.WorkingDirectory = aria2Dir;
                aria2cProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                aria2cProcess.StartInfo.CreateNoWindow = true;
                aria2cProcess.StartInfo.UseShellExecute = false;
                aria2cProcess.StartInfo.RedirectStandardOutput = true;
                aria2cProcess.StartInfo.RedirectStandardError = true;

                // 1. 绑定 Exited 事件（进程退出时触发）
                aria2cProcess.EnableRaisingEvents = true;  // 必须设置为 true 才能触发 Exited
                aria2cProcess.Exited += (sender, e) =>
                {
                    errorOutputCallback?.Invoke($"[Aria2c Exited] Exit Code: {aria2cProcess.ExitCode}, Time: {DateTime.Now}");
                    // 可以在这里记录日志或执行清理操作
                };

                // 2. 绑定 OutputDataReceived（标准输出）
                aria2cProcess.OutputDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data))
                    {
                        errorOutputCallback?.Invoke($"[Aria2c Output] {e.Data}");
                    }
                };

                // 3. 绑定 ErrorDataReceived（标准错误）
                aria2cProcess.ErrorDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data))
                    {
                        errorOutputCallback?.Invoke($"[Aria2c Error] {e.Data}");
                    }
                };

                // 启动进程并开始异步读取输出
                aria2cProcess.Start();
                aria2cProcess.BeginOutputReadLine();  // 开始异步读取标准输出
                aria2cProcess.BeginErrorReadLine();   // 开始异步读取标准错误
            }
            catch (Exception ex)
            {
                throw ex;
                // Logger.Debug(ex);
            }
        }

        #endregion
    }
}